package gdingtalk

import (
	"errors"
	"fmt"
	"gitee.com/zjlsliupei/ghelp"
	"github.com/tidwall/gjson"
	"time"
)

type Isv struct {
	option      string
	suiteId     int64
	suiteKey    string
	appId       int64
	suiteSecret string
	// 套件所属企业id
	suiteBelongCorpId string
}

// NewIsv 初始化isv
func NewIsv(option string) (Isv, error) {
	_json := gjson.Parse(option)
	return Isv{
		option:            option,
		suiteId:           _json.Get("suiteId").Int(),
		suiteKey:          _json.Get("suiteKey").String(),
		appId:             _json.Get("appId").Int(),
		suiteSecret:       _json.Get("suiteSecret").String(),
		suiteBelongCorpId: _json.Get("suiteBelongCorpId").String(),
	}, nil
}

// GetAccessToken 获取第三方企业id
func (i *Isv) GetAccessToken(corpId string) (string, error) {
	key := "access_token_" + corpId
	accessToken, _ := gCache.cGet(key)
	var err error
	if accessToken == "" {
		req := Post()
		timestamp := time.Now().Unix() * 1000
		var suiteTicket string
		suiteTicket, err = i.GetSuiteTicket()
		if err != nil {
			return "", err
		}
		str := fmt.Sprintf("%d\n%s", timestamp, suiteTicket)
		signature := ghelp.HmacSha256(str, i.suiteSecret)
		res := req.SetPath("/service/get_corp_token").
			AddQueryParam("accessKey", i.suiteKey).
			AddQueryParam("timestamp", ghelp.ToString(timestamp)).
			AddQueryParam("suiteTicket", suiteTicket).
			AddQueryParam("signature", signature).
			AddBodyParam("auth_corpid", corpId).
			Do()
		if res.IsSuccess() {
			accessToken = res.GetBody("access_token").String()
			gCache.cPut(key, accessToken, res.GetBody("expires_in").Int()-200)
		} else {
			err = errors.New(res.GetErrmsg())
		}
	}
	return accessToken, err
}

// GetSuiteTicket 获取套件ticket
func (i *Isv) GetSuiteTicket() (string, error) {
	key := fmt.Sprintf("suite_ticket_%d", i.suiteId)
	suiteTicket, _ := gCache.cGet(key)
	var err error
	if suiteTicket == "" {
		var openSyncBizData OpenSyncBizData
		res := db.Where("subscribe_id =?", fmt.Sprintf("%d_0", i.suiteId)).
			Where("corp_id = ?", i.suiteBelongCorpId).
			Where("biz_type = ?", 2).Find(&openSyncBizData)
		if res.Error != nil {
			err = errors.New("GetSuiteTicket err" + res.Error.Error())
		} else {
			suiteTicket = gjson.Get(openSyncBizData.BizData, "suiteTicket").String()
			gCache.cPut(key, suiteTicket, 86400*365)
		}
	}
	return suiteTicket, err
}

// GetAgentId 获取agentId
func (i *Isv) GetAgentId(corpId string) (int64, error) {
	key := fmt.Sprintf("agent_id_%d_%s", i.appId, corpId)
	agentId, _ := gCache.cGet(key)
	var err error
	if agentId == "" {
		res := i.GetCorpAuthInfo(corpId)
		if res.IsSuccess() {
			var _agentId int64
			res.GetBody("auth_info.agent").ForEach(func(key, value gjson.Result) bool {
				if value.Get("appid").Int() == i.appId {
					_agentId = value.Get("agentid").Int()
					return false
				}
				return true
			})
			if _agentId == 0 {
				err = errors.New("not exist agentId")
			} else {
				agentId = ghelp.ToString(_agentId)
				gCache.cPut(key, ghelp.ToString(_agentId), 86400*7)
			}
		} else {
			err = errors.New(res.GetErrmsg())
		}
	}
	return ghelp.ToInt(agentId), err
}

// GetCorpAuthInfo 获取企业授权信息
func (i *Isv) GetCorpAuthInfo(corpId string) Response {
	timestamp := time.Now().Unix() * 1000
	suiteTicket, err := i.GetSuiteTicket()
	if err != nil {
		return NewResponse(fmt.Sprintf(`{"errcode":20000,"errmsg":"%s"}`, err.Error()))
	}
	str := fmt.Sprintf("%d\n%s", timestamp, suiteTicket)
	signature := ghelp.HmacSha256(str, i.suiteSecret)
	return Post().SetPath("/service/get_auth_info").
		AddQueryParam("accessKey", i.suiteKey).
		AddQueryParam("timestamp", ghelp.ToString(timestamp)).
		AddQueryParam("suiteTicket", suiteTicket).
		AddQueryParam("signature", signature).
		AddBodyParam("suite_key", i.suiteKey).
		AddBodyParam("auth_corpid", corpId).
		Do()
}

func (i *Isv) GetSuiteAccessToken() (string, error) {
	key := fmt.Sprintf("suite_access_token_%d", i.suiteId)
	accessToken, _ := gCache.cGet(key)
	if accessToken != "" {
		return accessToken, nil
	}
	suiteTicket, err := i.GetSuiteTicket()
	if err != nil {
		return accessToken, fmt.Errorf(`{"errcode":20000,"errmsg":"%s"}`, err.Error())
	}
	res := Post().
		SetPath("/v1.0/oauth2/suiteAccessToken").
		AddBodyParam("suiteKey", i.suiteKey).
		AddBodyParam("suiteSecret", i.suiteSecret).
		AddBodyParam("suiteTicket", suiteTicket).
		Do2()
	if !res.IsSuccess() {
		return accessToken, errors.New(res.GetErrmsg())
	}
	accessToken = res.GetBody("accessToken").String()
	expireIn := res.GetBody("expireIn").Int()
	err = gCache.cPut(key, accessToken, expireIn-100)
	return accessToken, nil
}

// GetAuthInfo 获取企业开通应用后的授权信息
// 返回示例
// HTTP/1.1 200 OK
// Content-Type:application/json
//
//	{
//	 "authAppInfo" : {
//	   "agentList" : [ {
//	     "agentId" : 888,
//	     "agentName" : "小程序DEMO",
//	     "appId" : 111,
//	     "adminList" : [ "manager975" ]
//	   } ]
//	 },
//	 "authCorpInfo" : {
//	   "inviteCode" : "111",
//	   "industry" : "201",
//	   "corpName" : "小程序体验HTTP",
//	   "licenseCode" : "111",
//	   "authChannel" : "123",
//	   "authChannelType" : "1",
//	   "authLevel" : 1,
//	   "inviteUrl" : "https://wx.dingtalk.com/invite-page/xxx",
//	   "corpLogoUrl" : "https://static-legacy.dingtalk.com/xxx"
//	 },
//	 "authUserInfo" : {
//	   "userId" : "manager975"
//	 }
//	}
func (i *Isv) GetAuthInfo(authCorpId string) Response2 {
	suiteAccessToken, _ := i.GetSuiteAccessToken()
	return Get().
		AddHeaderParam("x-acs-dingtalk-access-token", suiteAccessToken).
		SetPath("/v1.0/oauth2/apps/authInfo").
		AddQueryParam("authCorpId", authCorpId).
		Do2()
}
